package com.xbts.common.utils.list;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xbts.common.utils.StringUtils;
import com.xbts.common.utils.bean.BeanUtils;
import java.util.List;
import java.util.function.Supplier;
import com.xbts.common.utils.reflect.GenericSuperclassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * List工具类
 */
public class ListUtils {

    private static final Logger log = LoggerFactory.getLogger(ListUtils.class);


    /**
     *
     * @param list 需要分割的集合
     * @param divideSize 每个List中含几个元素
     * @return
     */
    public static <T> List<List<T>> divideArrays(List<T> list, int divideSize){
        int splitCount=(list.size()+divideSize-1)/divideSize;
        return Stream.iterate(0, n -> n + 1)
                .limit(splitCount)
                .parallel()
                .map(a -> list.parallelStream().skip((long) a * divideSize).limit(divideSize).collect(Collectors.toList()))
                .filter(b -> !list.isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 获取有详细列表的list
     * @param list 列表的list
     * @param mapField 列表中的字段和详细表中对应的字段
     * @param detailService 详细表的service
     * @param queryWrapper 详细表的查询条件
     * @param <T> 列表的类型
     * @return mapField 分组的map
     */
    public static  <T> Map<String, Object> getChildrenItem(List<T> list, String mapField, IService<?> detailService, QueryWrapper queryWrapper) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        // mapField 组装为get方法
        String mapFieldGet = "get" + StringUtils.capitalize(mapField);
        Method declaredMethod = BeanUtils.findDeclaredMethod(list.get(0).getClass(), mapFieldGet);
        // 获取list中的mapField的值
        List<String> workIds = list.stream().map(item -> {
            try {
                if (declaredMethod != null) {
                    return declaredMethod.invoke(item).toString();
                }
            } catch (Exception e) {
                log.error("获取list中的mapField的值异常", e);
            }
            return null;
        }).collect(Collectors.toList());
        // 获取泛型的类型（实体类）
        // orderNum 转换为 order_num
        queryWrapper.in(StringUtils.toUnderScoreCase(mapField), workIds);

        List lst = detailService.list(queryWrapper);
        try {
            if (lst != null && lst.size() > 0) {
                Class<?> actualTypeArgument = GenericSuperclassUtil.getActualTypeArgument(detailService.getClass().getSuperclass(), 1);
                Method dbClassMethod = BeanUtils.findDeclaredMethod(actualTypeArgument, mapFieldGet);
                Map<String, Object> collect = (Map<String, Object>) lst.stream().collect(Collectors.groupingBy(item -> {
                    try {
                        if (dbClassMethod != null) {
                            return dbClassMethod.invoke(item).toString();
                        }
                    } catch (Exception e) {
                        log.error("获取list中的mapField的值异常", e);
                    }
                    return null;
                }));
                return collect;
            }
        }catch (Exception e){
            log.error("list转换map异常", e);
        }
        return null;
    }

    public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
        return copyListProperties(sources, target, null);
    }

    /**
     * @author zjk
     * 使用场景：Entity、Bo、Vo层数据的复制，因为BeanUtils.copyProperties只能给目标对象的属性赋值，却不能在List集合下循环赋值，因此添加该方法
     * 如：List<AdminEntity> 赋值到 List<AdminVo> ，List<AdminVo>中的 AdminVo 属性都会被赋予到值
     * S: 数据源类 ，T: 目标类::new(eg: AdminVo::new)
     */
    public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, ListBeanUtilsCallBack<S, T> callBack) {
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T t = target.get();
            org.springframework.beans.BeanUtils.copyProperties(source, t);
            if (callBack != null) {
                // 回调
                callBack.callBack(source, t);
            }
            list.add(t);
        }
        return list;
    }
}
